简单网格细分 1to4 Mesh Subdivision
0x00 引言
最近搞研究要用到网格模型,算法要求输入任意一个mesh模型,输出的细分模型里面所有的mesh边长面积足够小,形状不变,法线不变。
0x01 现有算法
网格细分(Mesh Subdivision)已经很多现成比较好的算法,例如Loop算法,Catmull-Clark算法。详情参考文末附录,这里先不详述。
这两个算法的缺点是对于三维的模型,细分后都会改变原有模型形状,细分后的mesh法线也会发生变化和原来有不同。这就不符合使用要求了。
如图所示
0x02 简单思路
不考虑效率的情况下,简单一变四1to4细分网格的做法是:
对每一个triangular mesh的每条边取中点形成新的顶点,然后分别连接相邻三个顶点形成新的细分三角形。
细分后的四个三角形的法线和原来三角形一致。
0x03 MATLAB实现
利用stlread读取.stl格式的数据之后,得到f, v, n三个参数。
f是三列的数据,每列指代(indicate)每一个三角形的三个顶点。坐标记录在v里面。
v也是三列的数据,每列是每个顶点的x,y,z的坐标。
n也是三列的数据,每列是法线的方向向量。
%% created by H_P 20181119: subdivide mesh into 4 smaller meshes in a simple manner
function [Divided_faces, Divided_vertices, Divided_n]=MeshSubD1to4(facesLarge, verticesLarge, nLarge)
mesh_length_Large=length(facesLarge);
Divided_faces=1:mesh_length_Large*4*3;
Divided_faces=(reshape(Divided_faces,[3,mesh_length_Large*4]))';
Divided_vertices=repelem(verticesLarge,4,1);
Divided_n=repelem(nLarge,4,1);
for n_for=1:mesh_length_Large
new_1=(verticesLarge((n_for-1)*3+1,:)+verticesLarge((n_for-1)*3+2,:))/2;
new_2=(verticesLarge((n_for-1)*3+3,:)+verticesLarge((n_for-1)*3+2,:))/2;
new_3=(verticesLarge((n_for-1)*3+1,:)+verticesLarge((n_for-1)*3+3,:))/2;
Divided_vertices((n_for-1)*12+2,:)= new_1;
Divided_vertices((n_for-1)*12+3,:)= new_3;
Divided_vertices((n_for-1)*12+4,:)= new_1;
Divided_vertices((n_for-1)*12+6,:)= new_2;
Divided_vertices((n_for-1)*12+7,:)= new_2;
Divided_vertices((n_for-1)*12+8,:)= new_3;
Divided_vertices((n_for-1)*12+10,:)= new_1;
Divided_vertices((n_for-1)*12+11,:)= new_2;
Divided_vertices((n_for-1)*12+12,:)= new_3;
end
end
效果如图,细分后没有改变原来形状和法线。
0x04 递归细分
一般情况下,输入模型的各个mesh的大小是不规则的话,则需要不停寻找过大的mesh并进行细分,这时候使用递归算法效率高些。
0x05 参考&其他
A Quick Introduction to Subdivision Surfaces
STLA_IO Read and Write Routines ASCII STL 3D Graphics Files
三维网格细分算法(Catmull-Clark subdivision & Loop subdivision)附源码
OpenGL 网格细分算法 Loop Subdivision - 附我的实现结果
վ HᴗP ի
This blog is under a CC BY-NC-SA 3.0 Unported License
Link to this article: https://hanspond.github.io/2018/11/27/简单网格细分 1to4 Mesh Subdivision/